home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / timidsrc.zip / tk_c.c < prev    next >
C/C++ Source or Header  |  1996-05-20  |  11KB  |  535 lines

  1. /*================================================================
  2.  *
  3.  * The Tcl/Tk interface for Timidity
  4.  * written by Takashi Iwai (iwai@dragon.mm.t.u-tokyo.ac.jp)
  5.  *
  6.  * Most of the following codes are derived from both motif_ctl.c
  7.  * and motif_pipe.c.  The communication between Tk program and
  8.  * timidity is established by a pipe stream as in Motif interface.
  9.  * On the contrast to motif, the stdin and stdout are assigned
  10.  * as pipe i/o in Tk interface.
  11.  *
  12.  *================================================================*/
  13.  
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <unistd.h>
  17. #include <stdarg.h>
  18. #include <string.h>
  19. #include <sys/ioctl.h>
  20.  
  21. #include "config.h"
  22. #include "common.h"
  23. #include "instrum.h"
  24. #include "playmidi.h"
  25. #include "output.h"
  26. #include "controls.h"
  27.  
  28.  
  29. static void ctl_refresh(void);
  30. static void ctl_total_time(int tt);
  31. static void ctl_master_volume(int mv);
  32. static void ctl_file_name(char *name);
  33. static void ctl_current_time(int ct);
  34. static void ctl_note(int v);
  35. static void ctl_program(int ch, int val);
  36. static void ctl_volume(int channel, int val);
  37. static void ctl_expression(int channel, int val);
  38. static void ctl_panning(int channel, int val);
  39. static void ctl_sustain(int channel, int val);
  40. static void ctl_pitch_bend(int channel, int val);
  41. static void ctl_reset(void);
  42. static int ctl_open(int using_stdin, int using_stdout);
  43. static void ctl_close(void);
  44. static int ctl_read(int32 *valp);
  45. static int cmsg(int type, int verbosity_level, char *fmt, ...);
  46. static void ctl_pass_playing_list(int number_of_files, char *list_of_files[]);
  47.  
  48. static void pipe_printf(char *fmt, ...);
  49. static void pipe_puts(char *str);
  50. static int pipe_gets(char *str, int maxlen);
  51. static void pipe_open();
  52. static void pipe_error(char *st);
  53. static int pipe_read_ready();
  54.  
  55. /**********************************************/
  56.  
  57. #define ctl tk_control_mode
  58.  
  59. ControlMode ctl= 
  60. {
  61.   "Tcl/Tk interface", 'k',
  62.   1,0,0,
  63.   ctl_open, ctl_pass_playing_list, ctl_close, ctl_read, cmsg,
  64.   ctl_refresh, ctl_reset, ctl_file_name, ctl_total_time, ctl_current_time, 
  65.   ctl_note, 
  66.   ctl_master_volume, ctl_program, ctl_volume, 
  67.   ctl_expression, ctl_panning, ctl_sustain, ctl_pitch_bend
  68. };
  69.  
  70.  
  71.  
  72. /***********************************************************************/
  73. /* Put controls on the pipe                                            */
  74. /***********************************************************************/
  75.  
  76. static int cmsg(int type, int verbosity_level, char *fmt, ...)
  77. {
  78.     char local[255];
  79.  
  80.     va_list ap;
  81.     if ((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&
  82.         ctl.verbosity<verbosity_level)
  83.         return 0;
  84.  
  85.     va_start(ap, fmt);
  86.     if (!ctl.opened) {
  87.         vfprintf(stderr, fmt, ap);
  88.         fprintf(stderr, "\n");
  89.     } else if (ctl.trace_playing) {
  90.         vsprintf(local, fmt, ap);
  91.         pipe_printf("CMSG %d", type);
  92.         pipe_puts(local);
  93.     }
  94.     va_end(ap);
  95.     return 0;
  96. }
  97.  
  98.  
  99. static void _ctl_refresh(void)
  100. {
  101.     /* pipe_int_write(REFRESH_MESSAGE); */
  102. }
  103.  
  104. static void ctl_refresh(void)
  105. {
  106.     if (ctl.trace_playing)
  107.         _ctl_refresh();
  108. }
  109.  
  110. static void ctl_total_time(int tt)
  111. {
  112.     int centisecs=tt/(play_mode->rate/100);
  113.     pipe_printf("TIME %d", centisecs);
  114. }
  115.  
  116. static void ctl_master_volume(int mv)
  117. {
  118.     pipe_printf("MVOL %d", mv);
  119. }
  120.  
  121. static void ctl_file_name(char *name)
  122. {
  123.     pipe_printf("FILE %s", name);
  124. }
  125.  
  126. static void ctl_current_time(int ct)
  127. {
  128.     int i,v;
  129.     int centisecs=ct/(play_mode->rate/100);
  130.  
  131.     if (!ctl.trace_playing) 
  132.         return;
  133.            
  134.     v=0;
  135.     i=voices;
  136.     while (i--)
  137.         if (voice[i].status!=VOICE_FREE) v++;
  138.     
  139.     pipe_printf("CURT %d %d", centisecs, v);
  140. }
  141.  
  142. static void ctl_note(int v)
  143. {
  144.     /*   int xl;
  145.     if (!ctl.trace_playing) 
  146.     return;
  147.     xl=voice[v].note%(COLS-24);
  148.     wmove(dftwin, 8+voice[v].channel,xl+3);
  149.     switch(voice[v].status)
  150.     {
  151.     case VOICE_DIE:
  152.         waddch(dftwin, ',');
  153.         break;
  154.     case VOICE_FREE: 
  155.         waddch(dftwin, '.');
  156.         break;
  157.     case VOICE_ON:
  158.         wattron(dftwin, A_BOLD);
  159.         waddch(dftwin, '0'+(10*voice[v].velocity)/128); 
  160.         wattroff(dftwin, A_BOLD);
  161.         break;
  162.     case VOICE_OFF:
  163.     case VOICE_SUSTAINED:
  164.         waddch(dftwin, '0'+(10*voice[v].velocity)/128);
  165.         break;
  166.     }
  167.     */
  168. }
  169.  
  170. static void ctl_program(int ch, int val)
  171. {
  172. /*  if (!ctl.trace_playing) 
  173.     return;
  174.   wmove(dftwin, 8+ch, COLS-20);
  175.   if (ISDRUMCHANNEL(ch))
  176.     {
  177.       wattron(dftwin, A_BOLD);
  178.       wprintw(dftwin, "%03d", val);
  179.       wattroff(dftwin, A_BOLD);
  180.     }
  181.   else
  182.     wprintw(dftwin, "%03d", val);
  183.     */
  184. }
  185.  
  186. static void ctl_volume(int channel, int val)
  187. {
  188.     /*
  189.       if (!ctl.trace_playing) 
  190.     return;
  191.   wmove(dftwin, 8+channel, COLS-16);
  192.   wprintw(dftwin, "%3d", (val*100)/127);
  193.   */
  194. }
  195.  
  196. static void ctl_expression(int channel, int val)
  197. {
  198. /*  if (!ctl.trace_playing) 
  199.     return;
  200.   wmove(dftwin, 8+channel, COLS-12);
  201.   wprintw(dftwin, "%3d", (val*100)/127);
  202.   */
  203. }
  204.  
  205. static void ctl_panning(int channel, int val)
  206. {
  207. /*  if (!ctl.trace_playing) 
  208.     return;
  209.   
  210.   if (val==NO_PANNING)
  211.     waddstr(dftwin, "   ");
  212.   else if (val<5)
  213.     waddstr(dftwin, " L ");
  214.   else if (val>123)
  215.     waddstr(dftwin, " R ");
  216.   else if (val>60 && val<68)
  217.     waddstr(dftwin, " C ");
  218.     */
  219. }
  220.  
  221. static void ctl_sustain(int channel, int val)
  222. {
  223. /*
  224.   if (!ctl.trace_playing) 
  225.     return;
  226.  
  227.   if (val) waddch(dftwin, 'S');
  228.   else waddch(dftwin, ' ');
  229.   */
  230. }
  231.  
  232. static void ctl_pitch_bend(int channel, int val)
  233. {
  234. /*  if (!ctl.trace_playing) 
  235.     return;
  236.  
  237.   if (val>0x2000) waddch(dftwin, '+');
  238.   else if (val<0x2000) waddch(dftwin, '-');
  239.   else waddch(dftwin, ' ');
  240.   */
  241. }
  242.  
  243. static void ctl_reset(void)
  244. {
  245. /*  int i,j;
  246.   if (!ctl.trace_playing) 
  247.     return;
  248.   for (i=0; i<16; i++)
  249.     {
  250.     ctl_program(i, channel[i].program);
  251.     ctl_volume(i, channel[i].volume);
  252.     ctl_expression(i, channel[i].expression);
  253.     ctl_panning(i, channel[i].panning);
  254.     ctl_sustain(i, channel[i].sustain);
  255.     ctl_pitch_bend(i, channel[i].pitchbend);
  256.     }
  257.   _ctl_refresh();
  258.   */
  259. }
  260.  
  261. /***********************************************************************/
  262. /* OPEN THE CONNECTION                                                */
  263. /***********************************************************************/
  264. static int ctl_open(int using_stdin, int using_stdout)
  265. {
  266.     ctl.opened=1;
  267.     ctl.trace_playing=1;    /* Default mode with Tcl/Tk interface */
  268.   
  269.     /* The child process won't come back from this call  */
  270.     pipe_open();
  271.  
  272.     return 0;
  273. }
  274.  
  275. /* Tells the window to disapear */
  276. static void ctl_close(void)
  277. {
  278.     if (ctl.opened) {
  279.         pipe_puts("QUIT");
  280.         ctl.opened=0;
  281.     }
  282. }
  283.  
  284.  
  285. /* 
  286.  * Read information coming from the window in a BLOCKING way
  287.  */
  288.  
  289. /* commands are: PREV, NEXT, QUIT, STOP, LOAD, JUMP, VOLM */
  290.  
  291. static int ctl_blocking_read(int32 *valp)
  292. {
  293.     char buf[256], *tok, *arg;
  294.     int rc;
  295.     int new_volume;
  296.     int new_centiseconds;
  297.  
  298.     rc = pipe_gets(buf, sizeof(buf)-1);
  299.     tok = strtok(buf, " ");
  300.  
  301.     while (1)/* Loop after pause sleeping to treat other buttons! */
  302.     {
  303.         switch (*tok) {
  304.         case 'V':
  305.             if ((arg = strtok(NULL, " ")) != NULL) {
  306.                 new_volume = atoi(arg);
  307.                 *valp= new_volume - amplification ;
  308.                 return RC_CHANGE_VOLUME;
  309.             }
  310.             return RC_NONE;
  311.           
  312.         case 'J':
  313.             if ((arg = strtok(NULL, " ")) != NULL) {
  314.                 new_centiseconds = atoi(arg);
  315.                 *valp= new_centiseconds*(play_mode->rate / 100) ;
  316.                 return RC_JUMP;
  317.             }
  318.             return RC_NONE;
  319.           
  320.         case 'Q':
  321.             return RC_QUIT;
  322.         
  323.         case 'L':
  324.             return RC_LOAD_FILE;          
  325.           
  326.         case 'N':
  327.             return RC_NEXT;
  328.           
  329.         case 'P':
  330.             /*return RC_REALLY_PREVIOUS;*/
  331.             return RC_PREVIOUS;
  332.           
  333.         case 'R':
  334.             return RC_RESTART;
  335.           
  336.         case 'F':
  337.             *valp=play_mode->rate;
  338.             return RC_FORWARD;
  339.           
  340.         case 'B':
  341.             *valp=play_mode->rate;
  342.             return RC_BACK;
  343.         }
  344.       
  345.       
  346.         if (*tok == 'S') {
  347.             pipe_gets(buf, sizeof(buf)-1);
  348.             tok = strtok(buf, " ");
  349.             if (*tok == 'S')
  350.                 return RC_NONE; /* Resume where we stopped */
  351.         }
  352.         else {
  353.             fprintf(stderr,"UNKNOWN RC_MESSAGE %s\n", tok);
  354.             return RC_NONE;
  355.         }
  356.     }
  357.  
  358. }
  359.  
  360. /* 
  361.  * Read information coming from the window in a non blocking way
  362.  */
  363. static int ctl_read(int32 *valp)
  364. {
  365.     int num;
  366.  
  367.     /* We don't wan't to lock on reading  */
  368.     num=pipe_read_ready(); 
  369.  
  370.     if (num==0)
  371.         return RC_NONE;
  372.   
  373.     return(ctl_blocking_read(valp));
  374. }
  375.  
  376. static void ctl_pass_playing_list(int number_of_files, char *list_of_files[])
  377. {
  378.     int i=0;
  379.     char local[1000];
  380.     int command;
  381.     int32 val;
  382.  
  383.     /* Pass the list to the interface */
  384.     pipe_printf("LIST %d", number_of_files);
  385.     for (i=0;i<number_of_files;i++)
  386.         pipe_puts(list_of_files[i]);
  387.     
  388.     /* Ask the interface for a filename to play -> begin to play automatically */
  389.     /*pipe_puts("NEXT");*/
  390.     command = ctl_blocking_read(&val);
  391.  
  392.     /* Main Loop */
  393.     for (;;)
  394.     { 
  395.         if (command==RC_LOAD_FILE)
  396.         {
  397.             /* Read a LoadFile command */
  398.             pipe_gets(local, sizeof(local)-1);
  399.             command=play_midi_file(local);
  400.         }
  401.         else
  402.         {
  403.             if (command==RC_QUIT) {
  404.                 /* if really QUIT */
  405.                 pipe_gets(local, sizeof(local)-1);
  406.                 if (*local == 'Z')
  407.                     return;
  408.                 /* only stop playing..*/
  409.             }
  410.             else if (command==RC_ERROR)
  411.                 command=RC_TUNE_END; /* Launch next file */
  412.         
  413.  
  414.             switch(command)
  415.             {
  416.             case RC_NEXT:
  417.                 pipe_puts("NEXT");
  418.                 break;
  419.             case RC_REALLY_PREVIOUS:
  420.                 pipe_puts("PREV");
  421.                 break;
  422.             case RC_TUNE_END:
  423.                 pipe_puts("TEND");
  424.                 break;
  425.             case RC_RESTART:
  426.                 pipe_puts("RSTA");
  427.                 break;
  428.             }
  429.             
  430.             command = ctl_blocking_read(&val);
  431.         }
  432.     }
  433. }
  434.  
  435.  
  436. /*
  437.  */
  438.  
  439. static int pipeAppli[2],pipePanel[2]; /* Pipe for communication with Tcl/Tk process   */
  440. static int fpip_in, fpip_out;    /* in and out depends in which process we are */
  441. static int pid;                   /* Pid for child process */
  442.  
  443. static void pipe_open()
  444. {
  445.     int res;
  446.     
  447.     res=pipe(pipeAppli);
  448.     if (res!=0) pipe_error("PIPE_APPLI CREATION");
  449.     
  450.     res=pipe(pipePanel);
  451.     if (res!=0) pipe_error("PIPE_PANEL CREATION");
  452.     
  453.     if ((pid=fork())==0)    /*child*/
  454.     {
  455.         close(pipePanel[1]); 
  456.         close(pipeAppli[0]);
  457.         
  458.         dup2(pipePanel[0], fileno(stdin));
  459.         close(pipePanel[0]);
  460.         dup2(pipeAppli[1], fileno(stdout));
  461.         close(pipeAppli[1]);
  462.         
  463.         execlp(WISH, WISH, "-f", TKPROGPATH, NULL);
  464.         /* Won't come back from here */
  465.         fprintf(stderr,"WARNING: come back from TkMidity\n");
  466.         exit(0);
  467.     }
  468.     
  469.     close(pipePanel[0]);
  470.     close(pipeAppli[1]);
  471.     
  472.     fpip_in= pipeAppli[0];
  473.     fpip_out= pipePanel[1];
  474. }
  475.  
  476.  
  477. static int pipe_read_ready()
  478. {
  479.     int num;
  480.     ioctl(fpip_in,FIONREAD,&num); /* see how many chars in buffer. */
  481.     return num;
  482. }
  483.  
  484.  
  485. /***********************************************************************/
  486. /* PIPE COMUNICATION                                                   */
  487. /***********************************************************************/
  488.  
  489. static void pipe_error(char *st)
  490. {
  491.     fprintf(stderr,"CONNECTION PROBLEM WITH TCL/TK PROCESS IN %s BECAUSE:%s\n",
  492.         st,
  493.         sys_errlist[errno]);
  494.     exit(1);
  495. }
  496.  
  497.  
  498. static void pipe_printf(char *fmt, ...)
  499. {
  500.     char buf[256];
  501.     va_list ap;
  502.     va_start(ap, fmt);
  503.     vsprintf(buf, fmt, ap);
  504.     pipe_puts(buf);
  505. }
  506.  
  507. static void pipe_puts(char *str)
  508. {
  509.     int len;
  510.     char lf = '\n';
  511.     len = strlen(str);
  512.     write(fpip_out, str, len);
  513.     write(fpip_out, &lf, 1);
  514. }
  515.  
  516.  
  517. int pipe_gets(char *str, int maxlen)
  518. {
  519. /* blocking reading */
  520.     char *p;
  521.     int len;
  522.  
  523.     /* at least 5 letters (4+\n) command */
  524.     len = 0;
  525.     for (p = str; ; p++) {
  526.         read(fpip_in, p, 1);
  527.         if (*p == '\n')
  528.             break;
  529.         len++;
  530.     }
  531.     *p = 0;
  532.     return len;
  533. }
  534.  
  535.